package ch.simplix.android.repetitive.implementation;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import android.util.Log;
import ch.simplix.android.repetitive.definition.RepeaterAction;
import ch.simplix.android.repetitive.definition.RepeaterStrategy;

public abstract class ARepeaterStrategy implements RepeaterStrategy {
	private ExecutorService singleThreadService;
	private long latestRepetition;
	private long updateIntervalInMillis;
	private final RepeaterAction repeaterAction;
	private static final String TAG = "ARepeaterStrategy";
	private final ActManager actManager;

	public ARepeaterStrategy(RepeaterAction repeaterAction) {
		this.repeaterAction = repeaterAction;
		this.singleThreadService = Executors.newSingleThreadExecutor();
		this.actManager = new ActManager();
	}

	protected RepeaterAction getRepeaterAction() {
		return repeaterAction;
	}

	protected void setUpdateInterval(long updateInterval, TimeUnit unit) {
		setUpdateInterval(0, updateInterval, unit);
	}

	public void setUpdateInterval(long latestRepetitionInMillis,
			long updateInterval, TimeUnit unit) {
		long newUpdateIntervalInMillis = unit.toMillis(updateInterval);
		if (newUpdateIntervalInMillis < 0) {
			newUpdateIntervalInMillis = 0;
		}
		if (this.updateIntervalInMillis == newUpdateIntervalInMillis)
			return;

		this.updateIntervalInMillis = newUpdateIntervalInMillis;
		if (this.updateIntervalInMillis != 0)
			prepareRepetition();
	}

	@Override
	public long getLatestRepetitionInMillis() {
		return latestRepetition;
	}

	@Override
	public long getNextRepetitionInMillis() {
		if (this.latestRepetition == 0) {
			return System.currentTimeMillis() + updateIntervalInMillis;
		}
		return (this.latestRepetition + updateIntervalInMillis);
	}

	@Override
	public long getUpdateIntervalInMillis() {
		return updateIntervalInMillis;
	}

	protected void act() {
		synchronized (this) {
			if (!actManager.isActing()) {
				singleThreadService.execute(actManager);
			}
		}

	}

	protected abstract void prepareRepetition();

	@Override
	public void finalize() {
		singleThreadService.shutdown();
	}

	class ActManager implements Runnable {
		private boolean isActing;

		public synchronized boolean isActing() {
			return isActing;
		}

		@Override
		public void run() {
			synchronized (this) {
				isActing = true;
			}
			WakeLockManager.s_acquire();
			try {
				if (getUpdateIntervalInMillis() == 0) {
					stopTimedRepetition();
					return;
				}
				latestRepetition = System.currentTimeMillis();
				repeaterAction.onRepeat();
			} finally {
				WakeLockManager.s_release();
				synchronized (this) {
					isActing = false;
				}
			}

		}
	}
}
